module App.Fossa.Report.AttributionSpec (
  spec,
) where

import App.Fossa.Report.Attribution
import Control.Applicative qualified as Ap
import Data.Aeson
import Data.Map.Strict (Map)
import Data.Text (Text)
import Hedgehog.Gen qualified as Gen
import Hedgehog.Range qualified as Range
import Test.Hspec
import Test.Hspec.Hedgehog

defaultRange :: Range Int
defaultRange = Range.linear 0 50

genLicense :: Gen License
genLicense =
  License . LicenseName
    <$> arbitraryText
    <*> Gen.maybe (LicenseContents <$> arbitraryText)

genProject :: Gen Project
genProject = Project <$> arbitraryText <*> arbitraryText

genDependency :: Gen Dependency
genDependency =
  Dependency
    <$> arbitraryText
    <*> arbitraryText
    <*> Gen.maybe arbitraryText
    <*> Gen.maybe Gen.bool
    <*> Gen.maybe arbitraryText
    <*> Gen.list defaultRange arbitraryText
    <*> Gen.maybe arbitraryText
    <*> Gen.maybe (Gen.list defaultRange genLicense)
    <*> Gen.list defaultRange genLicense
    <*> Gen.maybe arbitraryText
    <*> Gen.list defaultRange arbitraryText
    <*> Gen.list defaultRange arbitraryText
    <*> Gen.maybe arbitraryText
    <*> arbitraryText

genAttribution :: Gen Attribution
genAttribution =
  Attribution
    <$> genProject
    <*> Gen.list defaultRange genDependency
    <*> Gen.list defaultRange genDependency
    <*> genLicenseMap
    <*> Gen.maybe genCopyrightMap

tuplify :: Monad m => m a -> m b -> m (a, b)
tuplify = Ap.liftA2 (,)

genLicenseMap :: Gen (Map LicenseName LicenseContents)
genLicenseMap = do
  let genName = LicenseName <$> arbitraryText
  let genContents = LicenseContents <$> arbitraryText
  Gen.map defaultRange $ tuplify genName genContents

genCopyrightMap :: Gen (Map LicenseName [CopyrightText])
genCopyrightMap = do
  let genName = LicenseName <$> arbitraryText
  let genCopyright = CopyrightText <$> arbitraryText
  Gen.map defaultRange $ tuplify genName $ Gen.list defaultRange genCopyright

arbitraryText :: Gen Text
arbitraryText = Gen.text (Range.linear 3 25) Gen.unicodeAll

spec :: Spec
spec =
  describe "Attribution ToJSON/FromJSON instances" $
    modifyMaxSuccess (const 20) $
      it "are roundtrippable" $
        hedgehog $
          do
            attr <- forAll genAttribution
            roundtripJson attr

roundtripJson :: (MonadTest m, Show a, Eq a, ToJSON a, FromJSON a) => a -> m ()
roundtripJson a = tripping a toJSON fromJSON
